package com.artup.util.image;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.im4java.core.CompositeCmd;
import org.im4java.core.ConvertCmd;
import org.im4java.core.GMOperation;
import org.im4java.core.GraphicsMagickCmd;
import org.im4java.core.IM4JavaException;
import org.im4java.core.IMOperation;
import org.im4java.core.IdentifyCmd;
import org.im4java.process.ArrayListOutputConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.artup.pojo.ImageInfo;
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;


public class ImageUtil {
	private static final Logger LOGGER = LoggerFactory.getLogger(ImageUtil.class);
	/**
	 * 
	 * @param imagePath
	 *            图片路径
	 * @param Aw
	 *            宽度
	 * @param Ah
	 *            高度
	 * @param auto
	 *            是否自动按比例缩放图片,当为True时 图片只缩小不放大
	 * @return
	 */
	public static void processImage(Object srcImagePath, Object desImagePath,
			int Aw, int Ah, boolean auto) {
		GMOperation op = new GMOperation();
		GraphicsMagickCmd cmd = new GraphicsMagickCmd("convert");

		// 生成目标目录
		File reviewFile = new File(desImagePath.toString());
		if (!reviewFile.exists()) {// 新建目录
			reviewFile.getParentFile().mkdirs();
		}
		try {
			op.addImage(srcImagePath.toString());
			op.colorspace("RGB");
			op.density(100);
			// op.quality(90.0);
			// 按比例缩放图片 , 图片只缩小不放大
			if (auto) {
				op.resize(Aw, Ah, '>');
			} else {
				op.resize(Aw, Ah);
			}
			op.addRawArgs("+profile", "*");
			op.addImage(desImagePath.toString());
			cmd.run(op);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 处理图片旋转 如果RotateType是 1或者空值 不予处理，其他情况调用该方法
	 * @param imagePath
	 *            图片路径
	 * @param RotateType 1 正常 3 倒立 6 顺时针90度  8 逆时针90度 
	 *            旋转类型
	 * @return
	 */
	public static void processImageRotate(Object imagePath,String RotateType) {
		if(RotateType.equals("1"))
			return;
		GMOperation op = new GMOperation();
		GraphicsMagickCmd cmd = new GraphicsMagickCmd("convert");

		try {
			op.addImage(imagePath.toString());
			switch(RotateType){
				case "3":op.rotate(Double.parseDouble("180")); break;
				case "6":op.rotate(Double.parseDouble("-90")); break;
				case "8":op.rotate(Double.parseDouble("90")); break;
			}
			op.addRawArgs("+profile", "*");
			op.addImage(imagePath.toString());
			cmd.run(op);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 旋转（0° ~ 360°）
	 * @param orignalImagePath 原图路径
	 * @param newImagePath 旋转后的图片路径
	 * @param degree 旋转角度
	 * @return true-旋转成功；false-旋转失败；
	 */
	public static boolean rotate(String orignalImagePath, String newImagePath, double degree) {
		LOGGER.info("orignalImagePath = {}, newImagePath = {}", orignalImagePath, newImagePath);
		
		if(StringUtils.isBlank(orignalImagePath) || StringUtils.isBlank(newImagePath)) {
			return false;
		}
		
		// 1.将角度转换到0-360度之间
		degree = degree % 360;
		if (degree <= 0) {
			degree = 360 + degree;
		}
		
		IMOperation operation = new IMOperation();
		operation.addImage(orignalImagePath);
		operation.rotate(degree);
		operation.addImage(newImagePath);
		ConvertCmd ConvertCommand = new ConvertCmd(true);
		
		try {
			ConvertCommand.run(operation);
		} catch (IOException | InterruptedException | IM4JavaException e) {
			LOGGER.error("旋转图片 - 失败！", e);
			
			return false;
		}
		
		return true;
	}
	
	/**
	 * 裁切拖
	 * @param orignalImagePath 原图片路径
	 * @param newImagePath 裁切后的图片路径
	 * @param x 起始 X 坐标
	 * @param y 起始 Y 坐标
	 * @param width 裁切宽度
	 * @param height 裁切高度
	 * @return 成功-true；失败-false；
	 */
	public static boolean cutImage(String orignalImagePath, String newImagePath, int x, int y, int width, int height) {
		LOGGER.debug("================ 裁切图片 - begin ===================");
		LOGGER.info("orignalImagePath = {}, newImagePath = {}, x = {}, width = {}, height = {}", orignalImagePath, newImagePath, x, y, width, height);
		
		if(StringUtils.isBlank(orignalImagePath) || StringUtils.isBlank(newImagePath)) {
			return false;
		}
		
		IMOperation operation = new IMOperation();
		operation.addImage(orignalImagePath);
		/** width：裁剪的宽度 * height：裁剪的高度 * x：裁剪的横坐标 * y：裁剪纵坐标 */
		operation.crop(width, height, x, y);
		operation.addImage(newImagePath);
		ConvertCmd convertCommand = new ConvertCmd(true);
		
		try {
			convertCommand.run(operation);
		} catch (IOException | InterruptedException | IM4JavaException e) {
			LOGGER.error("剪切图片失败！", e);
			
			return false;
		}
		
		LOGGER.debug("================ 裁切图片 - end ===================");
		return true;
	}
	
	/**
	 * 图片信息
	 * 
	 * @param imagePath
	 * @return
	 */
	public static String showImageInfo(String imagePath) {
		String line = null;
		try {
			IMOperation op = new IMOperation();
			op.format("width:%w,height:%h,path:%d/%f,%b,%[EXIF:Model],%[EXIF:ISOSpeedRatings],%[EXIF:ColorSpace],%[EXIF:ApertureValue],%[EXIF:XResolution],%[EXIF:FocalLength],%[EXIF:ShutterSpeedValue],%[EXIF:XResolution],%[EXIF:Orientation],%[EXIF:DateTimeDigitized],%[EXIF:MeteringMode],%[EXIF:ExposureBiasValue]");
			op.addImage();
			IdentifyCmd identifyCmd = new IdentifyCmd(true);
			ArrayListOutputConsumer output = new ArrayListOutputConsumer();
			identifyCmd.setOutputConsumer(output);
			identifyCmd.run(op, imagePath);
			ArrayList<String> commandOutput = output.getOutput();
			assert commandOutput.size() == 1;
			line = commandOutput.get(0);

		} catch (Exception e) {
			e.printStackTrace();
		}
		return line;
	}

	/**
	 * 获取图片的宽高
	 * @param imagePath 原图片
	 * @return
	 */
	public static JSONObject getImagePixel(String imagePath) {
		if(StringUtils.isBlank(imagePath)) {
			return null;
		}
		
		JSONObject result = null;
		
		IMOperation imageMagickOption = new IMOperation();
		imageMagickOption.format("{width : %w, height : %h}");
		imageMagickOption.addImage();

		ArrayListOutputConsumer output = new ArrayListOutputConsumer();

		IdentifyCmd identifyCommand = new IdentifyCmd(true);
		identifyCommand.setOutputConsumer(output);
		
		try {
			identifyCommand.run(imageMagickOption, imagePath);
		} catch (IOException | InterruptedException | IM4JavaException e) {
			LOGGER.info("获取图片宽高 - 失败！", e);
			
			return null;
		}

		ArrayList<String> commandOutput = output.getOutput();
		
		if(1 == commandOutput.size() && StringUtils.isNotBlank(commandOutput.get(0))) {
			result = JSONObject.parseObject(commandOutput.get(0));
		}
		
		return result;
	}

	/**
	 * 根据尺寸缩放图片[等比例缩放:参数height为null,按宽度缩放比例缩放;参数width为null,按高度缩放比例缩放]
	 *
	 * @param originalImagePath 源图片路径
	 * @param newImagePath 处理后图片路径
	 * @param width 缩放后的图片宽度
	 * @param height 缩放后的图片高度
	 */
	public static boolean zoomImage(String originalImagePath, String newImagePath, Integer width, Integer height) {
		LOGGER.debug("================ 缩放图片 - begin ===================");
		LOGGER.info("originalImagePath = " + originalImagePath + ", newImagePath = " + newImagePath + ", width = " + width + ", height = " + height);
		
		if(StringUtils.isBlank(originalImagePath) || StringUtils.isBlank(newImagePath)) {
			return false;
		}

		IMOperation operation = new IMOperation();
		operation.addImage(originalImagePath);

		File reviewFile = new File(newImagePath);
		// 生成目标目录
		if (!reviewFile.exists()) {// 新建目录
			reviewFile.getParentFile().mkdirs();
		}

		if (width == null) {// 根据高度缩放图片
			operation.resize(null, height);
			LOGGER.info("按高度缩放");
		} else if (height == null) {// 根据宽度缩放图片
			operation.resize(width, null);
			LOGGER.info("按宽度缩放");
		} else {
//			operation.resize(width, height, ">");	// 不会放大
//			operation.resize(width, height, "<");	// 不会缩小
			operation.resize(width, height);
			LOGGER.info("按宽度缩放（可放大，也可以缩小）");
		}
		
		operation.addImage(newImagePath);
		ConvertCmd convert = new ConvertCmd(true);

		try {
			convert.run(operation);
		} catch (IOException | InterruptedException | IM4JavaException e) {
			LOGGER.error("缩放失败！", e);
			
			return false;
		}
		
		LOGGER.debug("================ 缩放图片 - end ===================");
		return true;
	}

	/**
	 * 组合图片
	 * @param imagePath_1 图层1路径 顶图
	 * @param imagePath_0 图层0 路径 底图
	 * @param newImagePath 合成图片路径
	 */
	public static void composeImage(String imagePath_1,String imagePath_0,String newImagePath ){
		GMOperation op = new GMOperation();
    	
    	op.gravity("center");
    	op.addImage();  
    	op.addImage();  
    	op.addImage();  
    	CompositeCmd composite = new CompositeCmd();
    	try {
			composite.run(op,imagePath_1,imagePath_0,newImagePath);
		} catch (IOException | InterruptedException | IM4JavaException e) {
			e.printStackTrace();
		}
	}
	
	
	  public static void main(String[] s){
		  //System.out.println(ImageUtil.showImageInfo("C:\\Users\\yachang\\Desktop\\1.jpg"));
//		  ImageUtil.processIosImageRotate("C:\\Users\\yachang\\Desktop\\0f4f0af81666b1544b53d7a4d3afc98eeb2e6081dcb8793735ddeed05f675203bb87747296df32f50baca462e70c03ed1495094531561.JPG");
//		  ImageUtil.zoomImage("http://image2.artup.com/original/2017-07-12/2183039/huace/685ee59915264704a4db096159f24d8f.jpg", "D:\\tmp\\target.jpg", 300, null);
		  
//		  String originalImagePaths [] = new String[2];
//		  originalImagePaths[0] = "http://test2.artup.com/original/2017-07-11/2183039/huace/aebdaa87e5d44f2a8c22e6c99cb4c114.jpg";
//		  originalImagePaths[1] = "http://test2.artup.com/original/2017-07-11/2183039/huace/3195b65277d14ad582482e48330aedf5.jpg";
		  
		  /*for(String originalImagePath : originalImagePaths) {
			  ImageUtil.zoomImage(originalImagePath, "D:\\tmp\\" + CommonUtils.UUIDGenerator() + ".jpg", 300, null);
		  }*/
		  
//		  int width = ImageUtil.getImageWidth("D:/tmp/original/2017/7/27/6666/dcbe55278aa44c0bbedde189b36b44c1.jpg");
//		  int height = ImageUtil.getImageHeight("D:/tmp/original/2017/7/27/6666/dcbe55278aa44c0bbedde189b36b44c1.jpg");
//		  System.out.println(width);
//		  System.out.println(height);
//		  ImageUtil.rotate("D:/tmp/original/2017/7/27/6666/dcbe55278aa44c0bbedde189b36b44c1.jpg", "D:/tmp/original/2017/7/27/6666/dcbe55278aa44c0bbedde189b36b44c2.jpg", 180);
//		  ImageUtil.cutImage("D:/Documents/Pictures/2.jpg", "D:/tmp/cutImage.jpg", 200, 350, 300, 200);
//		  ImageUtil.cutImage("D:/tmp/edited/rotated/2017/8/4/10000030/92739bd52b2d4da8a8917f417a4331c8.jpg", "D:/tmp/cutImage.jpg", 13, 2717, 3783, 3783);
//		  ImageUtil.cutImage("D:/tmp/edited/rotated/2017/8/4/10000030/92739bd52b2d4da8a8917f417a4331c8.jpg", "D:/tmp/cutImage.jpg", 1, 209, 3783, 3783);
//		  ImageUtil.zoomImage("D:/Documents/Pictures/2.jpg", "D:/tmp/123.jpg", 1004, null);
		  
		  String sourceImage = null;
		  String newImagePath = null;
		  sourceImage = "C:\\Users\\Administrator\\Desktop\\20170818_IMG_0250.jpg";
//			sourceImage = "D:\\Documents\\Pictures\\IMG_6954.jpg";
//		  sourceImage = "D:\\Documents\\Pictures\\two.jpg";
		  sourceImage = "D:\\Documents\\Pictures\\IMG_20170719_081255.jpg";
//		  ImageUtil.processIosImageRotate(sourceImage);
		  
		  sourceImage = "/data/images/original/2017/8/18/10000043/de2d4ef348bd47938f44ca3d1710c8f4.jpg";
		  newImagePath = "/data/images/original/2017/8/18/10000043/target.jpg";
		  
//		  sourceImage = "D:/tmp/original/2017/8/18/10000043/dc1ed4269452474b8712abd5f182642b.jpg";
//		  newImagePath = "D:/tmp/original/2017/8/18/10000043/target.jpg";
		  
		  ImageUtil.zoomImage(sourceImage, newImagePath, 3956, null);
	  }

	  /**
	   * 修正 iOS 拍摄的图片旋转问题
	   * @param imagePath 图片路径
	   */
	public static void processIosImageRotate(String imagePath){
		LOGGER.debug("================ 修正 iOS 拍摄的图片旋转 - begin ===================");
		
		LOGGER.info("imagePath = {}", imagePath);
		
		if(StringUtils.isBlank(imagePath)) {
			return;
		}
		
		ImageInfo imageInfo = ImageInfoUtil.parseImageInfo(imagePath);
		if(null == imageInfo) 
			return;
		if(!"Apple".equalsIgnoreCase(imageInfo.getLensMake())) 
			return;
		
		File jpegFile = new File(imagePath);
		
		Metadata metadata = null;
		try {
			metadata = JpegMetadataReader.readMetadata(jpegFile);
		} catch (JpegProcessingException | IOException e) {
			LOGGER.error("处理 iOS 拍摄的图片时失败！", e);
		}
		
		if(null == metadata){
			return;
		}
		
		for (Directory directory : metadata.getDirectories()) {
			if(null == directory) {
				continue;
			}
			
			if("Exif IFD0".equals(directory.getName())){
				for (Tag tag : directory.getTags()) {
					if("Orientation".equals(tag.getTagName())){
						String description = tag.getDescription();
						
						if(StringUtils.isBlank(description)) {
							continue;
						}
						
						String remarks[] = description.substring(description.indexOf("(") + 1, description.indexOf(")")).split(" ");
						
						if(null != remarks && 2 <= remarks.length && 3 >= remarks.length){
							LOGGER.info(remarks[0] + "\t" + remarks[1] + "\t");
							
							Pattern pattern = Pattern.compile("[0-9]*"); 
							Matcher isNum = pattern.matcher(remarks[1].trim());
							if(isNum.matches()){
								GMOperation operation = new GMOperation();
								GraphicsMagickCmd command = new GraphicsMagickCmd("convert");
								operation.addImage(imagePath);
								operation.rotate(Double.parseDouble(remarks[1].trim()));
								operation.quality(91D);//图片精度		
								operation.addRawArgs("+profile", "*");
								operation.addImage(imagePath.toString());
								try {
									command.run(operation);
								} catch (IOException | InterruptedException | IM4JavaException e) {
									LOGGER.error("修正 iOS 拍摄的图片旋转失败！", e);
								}
							} 
						}
					}
				} 
			}
		}	
		
		LOGGER.debug("================ 修正 iOS 拍摄的图片旋转 - end ===================");
	}
	
	/**
	 * 图片类型转换
	 * @param originalImagePath 原图片
	 * @param targetImagePath 目标图片
	 */
	public static void imageTypeConvert(String originalImagePath, String targetImagePath) {
		if(StringUtils.isEmpty(originalImagePath) || StringUtils.isEmpty(targetImagePath)) {
			return;
		}

		File targetImageFile = new File(targetImagePath);
		if (!targetImageFile.getParentFile().exists()) {
			targetImageFile.getParentFile().mkdir();
		}
		
		GMOperation graphicsMagickOption = new GMOperation();
		graphicsMagickOption.quality(100D);		// 不损失精度
		graphicsMagickOption.addImage(originalImagePath);
		graphicsMagickOption.addImage(targetImagePath);
		
		GraphicsMagickCmd ConvertCommand = new GraphicsMagickCmd("convert");
		try {
			ConvertCommand.run(graphicsMagickOption);
		} catch (IOException | InterruptedException | IM4JavaException e) {
			LOGGER.error("执行图片类型转换 - 失败！", e);
		}
	}

	/**
	 * 图片类型转换
	 * @param originalImagePath 原图片
	 * @param targetImagePath 目标图片
	 * @param precision 精度（0 ~ 100，值越大，精度越高）
	 */
	public static void imageTypeConvert(String originalImagePath, String targetImagePath, double precision) {
		if(StringUtils.isEmpty(originalImagePath) || StringUtils.isEmpty(targetImagePath)) {
			return;
		}

		File targetImageFile = new File(targetImagePath);
		if (!targetImageFile.getParentFile().exists()) {
			targetImageFile.getParentFile().mkdir();
		}
		
		if(0 == precision) {
			precision = 100D;
		}
		
		GMOperation graphicsMagickOption = new GMOperation();
		graphicsMagickOption.quality(precision);		// 指定精度
		graphicsMagickOption.addImage(originalImagePath);
		graphicsMagickOption.addImage(targetImagePath);
		
		ConvertCmd ConvertCommand = new ConvertCmd(true);
		/*String optionSystemName = System.getProperty("os.name").toLowerCase();
		System.out.println(optionSystemName);
	    if (optionSystemName.contains("windows")) {
	        // linux 下不要设置此值，不然会报错
	    	ConvertCommand.setSearchPath("D:\\commons\\GraphicsMagick");
	    }*/
		try {
			ConvertCommand.run(graphicsMagickOption);
		} catch (IOException | InterruptedException | IM4JavaException e) {
			LOGGER.error("执行图片类型转换 - 失败！", e);
		}
	}

	/**
	 * 图片类型转换
	 * @param originalImagePath 原图片
	 * @param targetImagePath 目标图片
	 */
	public static void imageTypeConvertForCompress(String originalImagePath, String targetImagePath) {
		if(StringUtils.isEmpty(originalImagePath) || StringUtils.isEmpty(targetImagePath)) {
			return;
		}
		
		File targetImageFile = new File(targetImagePath);
		if (!targetImageFile.getParentFile().exists()) {
			targetImageFile.getParentFile().mkdir();
		}
		
		GMOperation graphicsMagickOption = new GMOperation();
		graphicsMagickOption.addImage();
		graphicsMagickOption.addImage();
		
		ConvertCmd ConvertCommand = new ConvertCmd(true);
		try {
			ConvertCommand.run(graphicsMagickOption, originalImagePath, targetImagePath);
		} catch (IOException | InterruptedException | IM4JavaException e) {
			LOGGER.error("执行图片类型转换 - 失败！", e);
		}
		
	}

	
	
	
	
	
	
	
	
	
	/**
	 * 获取图片的宽度
	 * @param imagePath 图片路径
	 * @return 宽度
	 */
	public static int getImageWidth(String imagePath) {
		if(StringUtils.isBlank(imagePath)) {
			return 0;
		}
		
		int width = 0;	// 宽
		IMOperation operation = new IMOperation();
		operation.format("%w"); // 截取宽度
		operation.addImage(1);
		IdentifyCmd identifyCmd = new IdentifyCmd(true);
		ArrayListOutputConsumer arrayListOutputConsumer = new ArrayListOutputConsumer();
		identifyCmd.setOutputConsumer(arrayListOutputConsumer);
		try {
			identifyCmd.run(operation, imagePath);
		} catch (IOException e) {
			LOGGER.error("IO 错误！", e);
		} catch (InterruptedException e) {
			LOGGER.error("终止错误！", e);
		} catch (IM4JavaException e) {
			LOGGER.error("图片转 Java 异常！", e);
		}
		
		ArrayList<String> commandOutput = arrayListOutputConsumer.getOutput();
		assert commandOutput.size() == 1;
		width = Integer.parseInt(commandOutput.get(0));
		
		return width;
	}

	/**
	 * 获取图片的高度
	 * @param imagePath 图片路径
	 * @return 高度
	 */
	public static int getImageHeight(String imagePath) {
		if(StringUtils.isBlank(imagePath)) {
			return 0;
		}
		
		int height = 0;	// 高
		IMOperation operation = new IMOperation();
		operation.format("%h"); // 截取高度
		operation.addImage(1);
		IdentifyCmd identifyCmd = new IdentifyCmd(true);
		ArrayListOutputConsumer arrayListOutputConsumer = new ArrayListOutputConsumer();
		identifyCmd.setOutputConsumer(arrayListOutputConsumer);
		
		try {
			identifyCmd.run(operation, imagePath);
		} catch (IOException e) {
			LOGGER.error("IO 错误！", e);
		} catch (InterruptedException e) {
			LOGGER.error("终止错误！", e);
		} catch (IM4JavaException e) {
			LOGGER.error("图片转 Java 异常！", e);
		}
		
		ArrayList<String> commandOutput = arrayListOutputConsumer.getOutput();
		assert commandOutput.size() == 1;
		height = Integer.parseInt(commandOutput.get(0));
		
		return height;
	}
}
